home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Graphics / Plotting / Lyapunov / Source / LyapunovView.m < prev    next >
Text File  |  1995-06-12  |  10KB  |  339 lines

  1.  
  2. /* Generated by Interface Builder */
  3.  
  4. #import "LyapunovView.h"
  5. #import <math.h>
  6. #import <appkit/tiff.h>
  7. #import <appkit/color.h>
  8. #import <appkit/graphics.h>
  9. #import <appkit/Control.h>
  10. #import <appkit/Matrix.h>
  11. #import <appkit/NXColorWell.h>
  12. #import <dpsclient/psops.h>
  13. #import <appkit/Application.h>
  14. #import <dpsclient/psops.h>
  15. #import <dpsclient/wraps.h>
  16.  
  17.  
  18. @implementation LyapunovView
  19.  
  20. - initFrame:(const NXRect *)frm        // designated initializer for a view
  21. {
  22.     [super initFrame:frm];
  23.     return self;
  24. }
  25.  
  26. - appDidInit:sender                // final initialization
  27. {
  28.     // set up default colors
  29.     fromColor =  NXConvertRGBToColor(1.0, 1.0, 0.0);
  30.     toColor =  NXConvertRGBToColor(0.01, 0.01, 0.0);
  31.     backColor = NXConvertRGBToColor(0.0, 0.0, 0.05);
  32.     [fromShade setColor:fromColor];
  33.     [toShade setColor:toColor];
  34.     [backShade setColor:backColor];
  35.     
  36.     // set up plot type
  37.     singleDot = NO;
  38.     [plotType selectCellWithTag:singleDot];
  39.     
  40.     // set up default position
  41.     xPos = 0.0; yPos = 0.0;
  42.     [[posMatrix findCellWithTag:0] setFloatValue:xPos];
  43.     [[posMatrix findCellWithTag:1] setFloatValue:yPos];
  44.     
  45.     // set up default scale
  46.     xScale = 1.0; yScale = 1.0;
  47.     [[scaleMatrix findCellWithTag:0] setFloatValue:xScale];
  48.     [[scaleMatrix findCellWithTag:1] setFloatValue:yScale];
  49.     
  50.     // set up default initial value
  51.     initial = 0.1;
  52.     [[initialValue findCellWithTag:0] setFloatValue:initial];
  53.     
  54.     // set up default depth
  55.     deep = 4000;
  56.     [[depth findCellWithTag:0] setIntValue:deep];
  57.     
  58.     // set up default pattern
  59.     [[pattern findCellWithTag:0] setStringValue:"ab"];
  60.     
  61.     // set up contrast
  62.     [contrastText setFloatValue:2.0];
  63.     [contrastSlider setFloatValue:2.0];
  64.     
  65.     return self;
  66. }
  67.  
  68. - contrast:sender            // adjust image contrast coeff
  69. {
  70.     contrast = [sender floatValue];
  71.     [contrastText setFloatValue:contrast];
  72.     [contrastSlider setFloatValue:contrast];
  73.     
  74.     return self;
  75. }
  76.  
  77. - go:sender                // begin calculation of image
  78. {
  79.     register float total, t, tNew, r, a, b, expSum;
  80.     float spMul, rb, gb, bb, rd, gd, bd, rk, gk, bk;
  81.     register int ndx, x, n, pix, y, avgCnt;
  82.     NXRect pixel, line;
  83.     float log2 = log(2);
  84.     
  85.     pixel.size.width = 1;
  86.     pixel.size.height = 1;
  87.     line.size.height = 1;
  88.     line.size.width = XSIZE;
  89.     line.origin.x = 0;
  90.     
  91.     [self newParam:self];    // be sure we're up to date
  92.     
  93.     // set up color constants
  94.     rb = NXRedComponent(fromColor);
  95.     gb = NXGreenComponent(fromColor);
  96.     bb = NXBlueComponent(fromColor);
  97.     rd = NXRedComponent(toColor) - rb;
  98.     gd = NXGreenComponent(toColor) - gb;
  99.     bd = NXBlueComponent(toColor) - bb;
  100.     rk = NXRedComponent(backColor);
  101.     gk = NXGreenComponent(backColor);
  102.     bk = NXBlueComponent(backColor);
  103.     
  104.     // main calc loop: calc line & draw it.
  105.     expSum = 0; avgCnt = 0;
  106.     [self lockFocus];
  107.     for (y=0; y<YSIZE; y++) {
  108.         b = yPos + y*yScale/YSIZE; //  get physical y-coord
  109.         for (x=0; x<XSIZE; x++) {
  110.         a = xPos + x*xScale/XSIZE; //  get physical x-coord
  111.         total = 0.0; t = initial; ndx = 0;
  112.         for (n=0; n<deep; n++) {
  113.             r = (patternNum[ndx] ? a : b);
  114.             tNew = t * (1 - t) * r;
  115.         ndx++;
  116.         if (ndx >= patternLength) ndx = 0;
  117.         total += log(fabs(r - 2 * r * tNew)) / log2;
  118.         t = tNew;
  119.         }
  120.         space[x][y] = total / deep; // Lyapunov exponent approx.
  121.         // put into pixel map w/color        
  122.         pix = (x+(YSIZE-y-1)*XSIZE)*RGB;
  123.         if (total >= 0) {
  124.             pixels[pix] = 255 * rk;  // pix+RED = pix because RED=0
  125.         pixels[pix+GREEN] = 255 * gk;
  126.         pixels[pix+BLUE] = 255 * bk;
  127.         space[x][y] = 0;
  128.         } else {  // no chaos, so color it
  129.             spMul = fabs(space[x][y]/contrast);  // scale into color map
  130.         if (spMul > 1.0) spMul = 1.0;
  131.         if (fabs(space[x][y]) < 100000.0) {
  132.             expSum += space[x][y];
  133.             avgCnt++;
  134.         }
  135.         pixels[pix] = 255 *(spMul * rd + rb);
  136.             pixels[pix+GREEN]= 255*(spMul * gd + gb);
  137.             pixels[pix+BLUE] = 255*(spMul * bd + bb);
  138.         }
  139.         if (singleDot) {
  140.             // plot a pixel of it
  141.             pixel.origin.x = x;
  142.             pixel.origin.y = y;
  143.             NXImageBitmap(&pixel, 1, 1, 8, 3, 
  144.             NX_MESHED, NX_COLORMASK,
  145.             &pixels[(x+(YSIZE-y-1)*XSIZE)*RGB],
  146.             NULL, NULL, NULL, NULL);
  147.             [window flushWindow];
  148.             NXPing();
  149.         }
  150.     }
  151.     if (!singleDot) {
  152.         // plot a line of it
  153.         line.origin.y = y;
  154.         NXImageBitmap(&line, XSIZE, 1, 8, 3,
  155.             NX_MESHED, NX_COLORMASK, &pixels[(YSIZE-y-1)*XSIZE*RGB],
  156.         NULL, NULL, NULL, NULL);
  157.         [window flushWindow];
  158.         NXPing();
  159.     }
  160.     }
  161.     [self unlockFocus];
  162.     [avgOut setFloatValue:(expSum/avgCnt)];
  163.     [reApplyButton setEnabled:YES];
  164.     return self;
  165. }
  166.  
  167. - reApply:sender        // re do coloring on plot
  168. {
  169.     register int x, y, pix;
  170.     float rb, gb, bb, rd, gd, bd, rk, gk, bk;
  171.     float spMul;
  172.     NXRect pixel, line;
  173.     
  174.     [self newParam:self];    // be sure we're up to date
  175.     // set up plotting bounds
  176.     pixel.size.width = 1; pixel.size.height = 1;
  177.     line.size.height = 1; line.size.width = XSIZE;
  178.     line.origin.x = 0;
  179.     // get color params
  180.     rb = NXRedComponent(fromColor); gb = NXGreenComponent(fromColor);
  181.     bb = NXBlueComponent(fromColor); rd = NXRedComponent(toColor) - rb;
  182.     gd = NXGreenComponent(toColor) - gb; bd = NXBlueComponent(toColor) - bb;
  183.     rk = NXRedComponent(backColor); gk = NXGreenComponent(backColor);
  184.     bk = NXBlueComponent(backColor);
  185.     // re-apply colors
  186.     [self lockFocus];
  187.     for (y=0; y<YSIZE; y++) {
  188.         for (x=0; x<XSIZE; x++) {
  189.         pix = (x+(YSIZE-y-1)*XSIZE)*RGB;
  190.         if (space[x][y] >= 0) {
  191.             pixels[pix] = 255 * rk;  // pix+RED = pix because RED=0
  192.         pixels[pix+GREEN] = 255 * gk;
  193.         pixels[pix+BLUE] = 255 * bk;
  194.         } else {  // no chaos, so color it
  195.             spMul = fabs(space[x][y]/contrast);  // scale into color map
  196.         if (spMul > 1.0) spMul = 1.0;
  197.         pixels[pix] = 255 *(spMul * rd + rb);
  198.             pixels[pix+GREEN]= 255*(spMul * gd + gb);
  199.             pixels[pix+BLUE] = 255*(spMul * bd + bb);
  200.         }
  201.     }
  202.     // plot a line of it
  203.     line.origin.y = y;
  204.     NXImageBitmap(&line, XSIZE, 1, 8, 3,
  205.         NX_MESHED, NX_COLORMASK, &pixels[(YSIZE-y-1)*XSIZE*RGB],
  206.         NULL, NULL, NULL, NULL);
  207.     [window flushWindow];
  208.     NXPing();
  209.     } 
  210.     [self unlockFocus];   
  211.     return self;
  212. }
  213.  
  214. - newParam:sender            // set up new parameters for calc
  215. {
  216.     int count;
  217.     
  218.     // get colors
  219.     fromColor = [fromShade color];
  220.     toColor = [toShade color];
  221.     backColor = [backShade color];
  222.     
  223.     // get plotting method (dots or lines)
  224.     singleDot = [[plotType selectedCell] tag];
  225.     
  226.     // get x-y coordinates
  227.     xPos = [[posMatrix findCellWithTag:0] floatValue];
  228.     yPos = [[posMatrix findCellWithTag:1] floatValue];
  229.     
  230.     // get x-y scaling
  231.     xScale = [[scaleMatrix findCellWithTag:0] floatValue];
  232.     yScale = [[scaleMatrix findCellWithTag:1] floatValue];
  233.     
  234.     // get initial value for each point
  235.     initial = [[initialValue findCellWithTag:0] floatValue];
  236.     
  237.     // get depth
  238.     deep = [[depth findCellWithTag:0] intValue];
  239.     
  240.     // get pattern
  241.     patternString = [[pattern findCellWithTag:0] stringValue];
  242.     for(count=0; patternString[count]!='\0'; count++) {
  243.         patternNum[count] = ((patternString[count]=='a') ? 0 : 1);
  244.     }
  245.     patternLength = count;
  246.     return self;
  247. }
  248.  
  249. - drawSelf:(NXRect *)rects :(int)rectCount    // redraws the screen.
  250. {
  251.     PSsetgray(NX_DKGRAY);
  252.     NXRectFill(&bounds);
  253.     return self;
  254. }
  255.  
  256. - mouseDown:(NXEvent *)e    // stolen from MandelView.m
  257. /*
  258.  * We implement the mouseDown method so the user can sweep out a section of
  259.  * the view and select that as the current x,y,scale coordinates.
  260.  */
  261. {
  262.   int looping = YES;
  263.   int oldMask;
  264.   NXRect bbox;
  265.   NXPoint startPoint, currPoint;
  266.   double newX, newY, newDX, newDY;
  267.   NXCoord aspectRatio;
  268.   float mvX = xPos;
  269.   float mvY = yPos;
  270.   float mvDX = xScale;
  271.   float mvDY = yScale;
  272.   
  273.   aspectRatio = bounds.size.height / bounds.size.width;
  274.  
  275.   oldMask =  [window addToEventMask:NX_MOUSEDRAGGEDMASK];
  276.   startPoint = e->location;
  277.   [self convertPoint:&startPoint fromView:nil];
  278.   NXSetRect(&bbox,startPoint.x,startPoint.y,0.0,0.0);
  279.   [self lockFocus];
  280.   while (looping) {
  281.     e=[NXApp getNextEvent:NX_MOUSEUPMASK | NX_MOUSEDRAGGEDMASK];
  282.     currPoint = e->location;
  283.     [self convertPoint:&currPoint fromView:nil];
  284.     bbox.size.width = 2*(currPoint.x - startPoint.x);
  285.     bbox.size.height = 2*(currPoint.y - startPoint.y);
  286.     /* Normalize bbox to always have positive width and height */
  287.     if (bbox.size.width < 0) bbox.size.width = -bbox.size.width;
  288.     if (bbox.size.height < 0) bbox.size.height = -bbox.size.height;
  289.     /*
  290.      * constrain the box to have the aspect ratio of the view.  Choose
  291.      * whichever dimension is closer to the desired result.
  292.      */
  293.     if ((bbox.size.height/bbox.size.width) > aspectRatio) {
  294.       bbox.size.height = bbox.size.width * aspectRatio;
  295.     } else {
  296.       bbox.size.width = bbox.size.height / aspectRatio;
  297.     }
  298.     /* The startPoint is always at the center of the bbox */
  299.     bbox.origin.x = startPoint.x - .5 * bbox.size.width;
  300.     bbox.origin.y = startPoint.y - .5 * bbox.size.height;
  301.     PSnewinstance();
  302.     if (looping = (e->type == NX_MOUSEDRAGGED)) {
  303.       PSsetinstance(YES);
  304.       PSsetgray(NX_WHITE);
  305.       NXFrameRect(&bbox);
  306.       PSsetinstance(NO);
  307.     }
  308.   }
  309.   [self unlockFocus];
  310.   [window setEventMask:oldMask];
  311.   if ((bbox.size.width > 0) && (bbox.size.height > 0)) {
  312.     /*
  313.      * At this point, bbox is in window coordinates.  Set new controller
  314.      * parameters based on this view's coordinates and the bounding box.
  315.      */
  316.     newDX = (bbox.size.width*mvDX)/bounds.size.width;
  317.     newDY = (bbox.size.height*mvDY)/bounds.size.height;
  318.     newX = ((startPoint.x + bounds.origin.x) / bounds.size.width);
  319.     newX = newX * mvDX + mvX - newDX/2;
  320.     newY = ((startPoint.y + bounds.origin.y) / bounds.size.height);
  321.     newY = newY * mvDY + mvY - newDY/2;
  322.  
  323.     /*
  324.      * Note that we only update the text fields -- we
  325.      * don't update the internal instance variables.  If we were to update
  326.      * the internal ivs, then the user would only get one chance with the
  327.      * mouse down method because subsequent mouse-downs would work in terms
  328.      * of the new coordinate system.
  329.      */
  330.     [[posMatrix findCellWithTag:0] setFloatValue:newX];
  331.     [[posMatrix findCellWithTag:1] setFloatValue:newY];
  332.     [[scaleMatrix findCellWithTag:0] setFloatValue:newDX];
  333.     [[scaleMatrix findCellWithTag:1] setFloatValue:newDY];
  334.   }
  335.   return self;
  336. }
  337.  
  338. @end
  339.